package com.sc.server.system.common.config.mybatisPls;

import java.util.Arrays;
import java.util.List;

import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.plugins.parser.tenant.TenantSqlParser;
import com.sc.common.SpringContextUtils;
import com.sc.server.system.common.bean.MybatisPlusConstant;
import com.sc.server.system.common.bean.SpecialTables;
import com.sc.server.system.common.utils.UserUtils;
import net.sf.jsqlparser.expression.*;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
import net.sf.jsqlparser.expression.operators.relational.SupportsOldOracleJoinSyntax;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.SelectExpressionItem;
import net.sf.jsqlparser.statement.select.SubSelect;
import net.sf.jsqlparser.statement.update.Update;
import org.springframework.beans.factory.annotation.Autowired;
/**
 * <p>
 * 复写租户条件
 * 使用当前版本为3.1.2
 * </p>
 * @author yuxiaobin
 * @date 2019/8/1
 */
public class MyTenantParser extends TenantSqlParser {
    @Autowired
    private static SpecialTables specialTables=null;
    /**
     * 目前无法处理多租户的字段加上表别名
     * @param expression
     * @param table
     * @return
     */
    protected Expression processTableAlias(Expression expression, Table table) {
        InExpression inExpression=(InExpression) expression;
        if(table.getAlias()!=null){
            inExpression.setLeftExpression(new Column(table.getAlias()+"."+"tenant_id"));
        }

        return inExpression;
    }
    @Override
    public  void processInsert(Insert insert){
        return;
    }
    /**
     * <p>
     * update 语句处理
     * </p>
     */
    @Override
    public void processUpdate(Update update) {
        List<Table> tableList = update.getTables();
        if (null == tableList || tableList.size() >= 2) {
            throw new MybatisPlusException("Failed to process multiple-table update, please exclude the statementId");
        }
        Table table = tableList.get(0);
        if (this.getTenantHandler().doTableFilter(table.getName())) {
            // 过滤退出执行
            return;
        }
        Expression expression = this.expression(table, update.getWhere());
        if(expression!=null){
            update.setWhere(expression);
        }
    }
    /**
     * <p>
     * delete 语句处理
     * </p>
     */
    @Override
    public void processDelete(Delete delete) {
        if (this.getTenantHandler().doTableFilter(delete.getTable().getName())) {
            // 过滤退出执行
            return;
        }
        Expression expression = this.expression(delete.getTable(), delete.getWhere());
        if(expression!=null){
            delete.setWhere(expression);
        }
    }
    /**
     * <p>
     * delete update 语句 where 处理
     * </p>
     */
    protected Expression expression(Table table, Expression where) {
        //获得where条件表达式
        Expression tenant=null;
        if(!UserUtils.getTenantId().equals( MybatisPlusConstant.TENANT_ID_DEFAULT)){
            if(specialTables==null){
                specialTables= SpringContextUtils.getBean("specialTables",SpecialTables.class);
            }
            if(specialTables.getTenantTables()!=null && Arrays.asList(specialTables.getTenantTables().split(","))
                    .contains(table.getName())){
                tenant=getTenantHandler().getTenantId();
                EqualsTo equalsTo=new EqualsTo();
                equalsTo.setLeftExpression(new Column(MybatisPlusConstant.TENANT_ID));
                equalsTo.setRightExpression(new StringValue(UserUtils.getTenantId()));
                tenant=equalsTo;
            }else {
                tenant=getTenantHandler().getTenantId();

            }

        }
        if (null != where) {
          if(tenant==null){
              return where;
          }
            return new AndExpression(tenant, where);
        }
       /* equalsTo.setLeftExpression(this.getAliasColumn(table));
        equalsTo.setRightExpression(getTenantHandler().getTenantId());*/
        return tenant;
    }
    /**
     * 默认是按 tenant_id=1 按等于条件追加
     *
     * @param currentExpression 现有的条件：比如你原来的sql查询条件
     * @param table
     * @return
     */
    @Override
    protected Expression builderExpression(Expression currentExpression, Table table) {
        final Expression tenantExpression = this.getTenantHandler().getTenantId();
        Expression appendExpression=null;
            if (!(tenantExpression instanceof SupportsOldOracleJoinSyntax)) {
                if(tenantExpression!=null){
                    appendExpression = new EqualsTo();
                    ((EqualsTo) appendExpression).setLeftExpression(this.getAliasColumn(table));
                    ((EqualsTo) appendExpression).setRightExpression(tenantExpression);
                }else{
                    appendExpression = new EqualsTo();
                    ((EqualsTo) appendExpression).setLeftExpression(new Column("1"));
                    ((EqualsTo) appendExpression).setRightExpression(new Column("1"));
                }

            } else {
                appendExpression = processTableAlias(tenantExpression, table);
            }

        if (currentExpression == null) {
            return appendExpression;
        }
        if (currentExpression instanceof BinaryExpression) {
            BinaryExpression binaryExpression = (BinaryExpression) currentExpression;
            if (binaryExpression.getLeftExpression() instanceof FromItem) {
                processFromItem((FromItem) binaryExpression.getLeftExpression());
            }
            if (binaryExpression.getRightExpression() instanceof FromItem) {
                processFromItem((FromItem) binaryExpression.getRightExpression());
            }
        } else if (currentExpression instanceof InExpression) {
            InExpression inExp = (InExpression) currentExpression;
            ItemsList rightItems = inExp.getRightItemsList();
            if (rightItems instanceof SubSelect) {
                processSelectBody(((SubSelect) rightItems).getSelectBody());
            }
        }
        if (currentExpression instanceof OrExpression) {
            return new AndExpression(new Parenthesis(currentExpression), appendExpression);
        } else {
            return new AndExpression(currentExpression, appendExpression);
        }
    }
    @Override
    protected void processPlainSelect(PlainSelect plainSelect, boolean addColumn) {
        FromItem fromItem = plainSelect.getFromItem();
        if (fromItem instanceof Table) {
            Table fromTable = (Table) fromItem;
            if (!this.getTenantHandler().doTableFilter(fromTable.getName())) {
                plainSelect.setWhere(builderExpression(plainSelect.getWhere(), fromTable));
                if (addColumn) {
                    plainSelect.getSelectItems().add(new SelectExpressionItem(new Column(this.getTenantHandler().getTenantIdColumn())));
                }
            }
        } else {
            processFromItem(fromItem);
        }
        List<Join> joins = plainSelect.getJoins();
        if (joins != null && joins.size() > 0) {
            joins.forEach(j -> {
                processJoin(j);
                processFromItem(j.getRightItem());
            });
        }
    }
}
